#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/spinlock.h>
#include <linux/rwlock.h>
#include <linux/types.h>
#include <linux/ioctl.h>
#include <linux/list.h>
#include <linux/slab.h>

#define MAX_DATA_BUF   3
#define MAX_DATA_LEN   200

#define LUAN_TEST_MAGIC    'L'
#define LUAN_TEST_CMD_MAX   5
#define READ_LENGTH_CMD _IOR(LUAN_TEST_MAGIC,  1, int)

#define USE_LIST 0

static int major = 0; /*静态设备号方式的默认值*/
static int minor = 0;    /**/
module_param(major,int,S_IRUGO);
module_param(minor,int,S_IRUGO);

static int user_read_len = 100;
module_param(user_read_len,int,S_IRUGO);

struct mylink_data{
    struct list_head list;
    int num;
    int data_len;
    char *data;
};


struct mydev_data
{
    unsigned char data_flag;
    unsigned int data_len;
    char data[MAX_DATA_LEN];
};

struct C_Dev
{
    struct cdev *char_cdev;  /*cdev数据结构*/
    dev_t devno;    /*设备编号*/
    struct class *char_cdev_class;
    struct device *char_cdev_device;
    atomic_t cdev_has_data;
    
    unsigned char char_dev_data_total_used;
    unsigned int char_dev_data_w_index;
    unsigned int char_dev_data_r_index;
    rwlock_t cdev_rw_lock[MAX_DATA_BUF];
    struct mydev_data char_dev_data[MAX_DATA_BUF];
    struct mylink_data list_dev_data;
    rwlock_t list_rw_lock;
};

wait_queue_head_t cdev_wait;
struct mylink_data char_link_data;

struct C_Dev char_device;

#define DEVICE_NAME    "character_device"

char databuf[100];
char read_buf[100];
int read_sig;
int write_sig;

void char_dev_data_init(void)
{
    unsigned int i ;
    //struct mylink_data *plist_data;
    for(i = 0;i<MAX_DATA_BUF;i++)
    {
        char_device.char_dev_data[i].data_flag = 0;
        char_device.char_dev_data[i].data_len = 0;
        char_device.char_dev_data_w_index = 0;
        char_device.char_dev_data_r_index = 0;
        char_device.char_dev_data_total_used = 0;
    }
    INIT_LIST_HEAD(&char_device.list_dev_data.list);
    char_device.list_dev_data.num = 0;
    //plist_data = (struct mylink_data*)kmalloc(sizeof(struct mylink_data),GFP_KERNEL);
    //list_add_tail(&plist_data->list,&char_device.list_dev_data.list);
}



static int char_cdev_open(struct inode *inode,struct file *file)
{
    try_module_get(THIS_MODULE);
    dev_warn(char_device.char_cdev_device,"opened!\n");
    file->private_data = &char_device;
    return 0;
}
static int char_cdev_release(struct inode *inode,struct file *file)
{

    dev_warn(char_device.char_cdev_device,"closed!\n");
    module_put(THIS_MODULE);
    return 0;
}
static ssize_t char_cdev_read(struct file *file,char *buf,size_t count,loff_t *f_ops)
{
    
    long ret=0;
    struct C_Dev *cdev = file->private_data;
    unsigned long rw_flag;
#if(USE_LIST == 0)
    unsigned int read_index = cdev->char_dev_data_r_index;
#endif
#if(USE_LIST == 1)
    struct mylink_data *plist_data;
    struct list_head *pos;
#endif
//    read_sig = atomic_read(&cdev->cdev_has_data);
#if (USE_LIST==0)
    count = cdev->char_dev_data[read_index].data_len;
#endif 
    dev_warn(cdev->char_cdev_device,"read method!\n");
    //dev_warn(cdev->char_cdev_device,"character driver read_sig:%d,r_index:%d\n",cdev->char_dev_data_total_used,cdev->char_dev_data_r_index);
    if(file->f_flags & O_NONBLOCK)/*非阻塞*/
    {
        #if (USE_LIST==0)
        if((cdev->char_dev_data_total_used !=0))/*有数据,可读写*/
        {
            read_lock_irqsave(&cdev->cdev_rw_lock[read_index],rw_flag);
            ret = raw_copy_to_user(buf,&cdev->char_dev_data[read_index].data[0],count);
            dev_warn(cdev->char_cdev_device,"read data:%s len:%ld!\n",cdev->char_dev_data[read_index].data,count);
            if(ret < 0)
            {
                dev_err(cdev->char_cdev_device,"kernel read failed!\n");
                return -EFAULT;
            }
            
            //atomic_dec(&cdev->cdev_has_data);
            cdev->char_dev_data_r_index++;
            if(cdev->char_dev_data_r_index >= MAX_DATA_BUF)
            {
                cdev->char_dev_data_r_index = 0;
            }
            read_unlock_irqrestore(&cdev->cdev_rw_lock[read_index],rw_flag);
        }
        else
        {
            return -EFAULT;
        }
        #else
        if(list_empty(&cdev->list_dev_data.list))/*链表为空，无数据读取*/
        {
            dev_warn(cdev->char_cdev_device,"empty list \n");
            return -EFAULT;
        }
        else
        {
            //read_lock_irqsave(&cdev->cdev_rw_lock[read_index],rw_flag);
            list_for_each(pos,&cdev->list_dev_data.list){
                plist_data = list_entry(pos,struct mylink_data,list);
                if(plist_data->data != NULL)
                dev_warn(cdev->char_cdev_device,"read data:%s len:%d!\n",plist_data->data,plist_data->data_len);
                break;
            }
            if(plist_data->data != NULL)
            ret = raw_copy_to_user(buf,plist_data->data,plist_data->data_len);
            dev_warn(cdev->char_cdev_device,"read data:%s len:%d!\n",buf,plist_data->data_len);
            if(ret < 0)
            {
                dev_err(cdev->char_cdev_device,"kernel read failed!\n");
                return -EFAULT;
            }
            //kfree(plist_data->data);
            list_del(&plist_data->list);
            //read_unlock_irqrestore(&cdev->cdev_rw_lock[read_index],rw_flag);
        }
        #endif
    }
    else/*阻塞*/
    {
        #if (USE_LIST==0)
        if((cdev->char_dev_data_total_used !=0))/*有数据，可读写*/
        {

        }
        else
        {
            dev_warn(cdev->char_cdev_device,"character deiver into sleep,sig:%d??\n",read_sig);
            //while(read_sig == 0)
            //{
                read_sig = 0;
                //read_sig = atomic_read(&cdev->cdev_has_data);
                dev_warn(cdev->char_cdev_device,"character driver while read cnt:%d\n",read_sig);
                wait_event_interruptible(cdev_wait,read_sig);
                
                dev_warn(cdev->char_cdev_device,"read:out of sleep direct run here?\n");
            //}
            
        }
        read_lock_irqsave(&cdev->cdev_rw_lock[read_index],rw_flag);
        ret = raw_copy_to_user(buf,&cdev->char_dev_data[read_index].data[0],count);
        dev_warn(cdev->char_cdev_device,"read data:%s len:%ld,used:%d,index:%d!\n",cdev->char_dev_data[read_index].data,count,cdev->char_dev_data_total_used,cdev->char_dev_data_w_index);
        if(ret < 0)
        {
            dev_err(cdev->char_cdev_device,"kernel read failed!\n");
            return -EFAULT;
        }
        
        //atomic_dec(&cdev->cdev_has_data);
        cdev->char_dev_data_r_index++;
        if(cdev->char_dev_data_r_index >= MAX_DATA_BUF)
        {
            cdev->char_dev_data_r_index = 0;
        } 
        if(cdev->char_dev_data_total_used >= MAX_DATA_BUF)
        {
            write_sig = 1;
            wake_up_interruptible(&cdev_wait);
            dev_warn(cdev->char_cdev_device,"wake up write event\n");
        }
        if(cdev->char_dev_data_total_used != 0)
        {
            cdev->char_dev_data_total_used--;
        }
        read_unlock_irqrestore(&cdev->cdev_rw_lock[read_index],rw_flag);
        #else
        //if(list_empty(&cdev->list_dev_data.list))/*链表为空，无数据读取*/
        {
            dev_warn(cdev->char_cdev_device,"character deiver into sleep,sig:%d??\n",read_sig);

            read_sig = 0;
            //read_sig = atomic_read(&cdev->cdev_has_data);
            dev_warn(cdev->char_cdev_device,"character driver while read cnt:%d\n",read_sig);
            //wait_event_interruptible(cdev_wait,read_sig);
            
            dev_warn(cdev->char_cdev_device,"read:out of sleep direct run here?\n");

        }
        //else/*有数据，可读取*/
        {
            
        }
        //read_lock_irqsave(&cdev->cdev_rw_lock[read_index],rw_flag);
        //plist_data = (struct mylink_data *)&cdev->list_dev_data;
        list_for_each(pos,&cdev->list_dev_data.list){
            plist_data = list_entry(pos,struct mylink_data,list);
            if(plist_data->data != NULL)
            {
                dev_warn(cdev->char_cdev_device,"read data:%s len:%d!\n",plist_data->data,plist_data->data_len);
            }
            else
            {
                dev_warn(cdev->char_cdev_device,"read data:error!\n");
            }
            break;
        }
        if(plist_data->data != NULL)
        {
            ret = raw_copy_to_user(buf,plist_data->data,plist_data->data_len);
            dev_warn(cdev->char_cdev_device,"read data:%s len:%d!\n",buf,plist_data->data_len);
            if(ret < 0)
            {
                dev_err(cdev->char_cdev_device,"kernel read failed!\n");
                return -EFAULT;
            }
        }

        kfree(plist_data->data);
        list_del(&plist_data->list);

        write_sig = 1;
        //wake_up_interruptible(&cdev_wait);
        dev_warn(cdev->char_cdev_device,"wake up write event\n");
        //read_unlock_irqrestore(&cdev->cdev_rw_lock[read_index],rw_flag);
        #endif
    }

    return ret;
}
static ssize_t char_cdev_write(struct file *file,const char *buf,size_t count,loff_t *f_ops)
{
    
    unsigned long rw_flag;
    long ret;
    struct C_Dev *char_dev= file->private_data;
    unsigned int write_index;
#if(USE_LIST == 1)
    struct mylink_data *plist_data;
    struct mylink_data *p;
    struct list_head *pos;
#endif    
#if(USE_LIST == 0)
    write_index = char_dev->char_dev_data_w_index;
#endif
    dev_warn(char_dev->char_cdev_device,"write mothod!\n");
#if(USE_LIST == 1)
    if(0/*list_is_last(&char_dev->list_dev_data.list,&char_dev->list_dev_data.list)*/)/*最后一个链表*/
    {
        dev_warn(char_dev->char_cdev_device,"write:list is last\n");
        write_sig = 0;
        wait_event_interruptible(cdev_wait,write_sig);
        
        dev_warn(char_dev->char_cdev_device,"write:out of sleep run here\n");
    }
    else
    {
    }
    if(count > MAX_DATA_LEN)
    {
        count = MAX_DATA_LEN;
    }
    //write_lock_irqsave(&char_dev->cdev_rw_lock[write_index],rw_flag);
    plist_data = (struct mylink_data *)kmalloc(sizeof(plist_data),GFP_ATOMIC);
    plist_data->data = (unsigned char*)kmalloc(count,GFP_ATOMIC);
    plist_data->data_len = count;
    ret = raw_copy_from_user(plist_data->data,buf,count);

    //dev_warn(char_dev->char_cdev_device,"write data:%s,len:%ld,used:%d,index:%d!\n",buf,count,0,0);
    list_add_tail(&plist_data->list,&char_dev->list_dev_data.list);
    if(ret < 0)
    {
        dev_err(char_dev->char_cdev_device,"kernel write failed!\n");
        return -EFAULT;
    }
    user_read_len = count;
    //char_dev->char_dev_data[write_index].data_len = count;
    list_for_each(pos,&char_dev->list_dev_data.list){
        p = list_entry(pos,struct mylink_data,list);
        dev_warn(char_dev->char_cdev_device,"kernel write data:%s",p->data);
    }
    #if 0
    if(char_dev->char_dev_data_total_used == 0)/*buffer 空，唤醒阻塞的读信号*/
    {
        read_sig = 1;
        wake_up_interruptible(&cdev_wait);
        dev_warn(char_dev->char_cdev_device,"wake up read event\n");
    }
    #endif
    //write_unlock_irqrestore(&char_dev->cdev_rw_lock[write_index],rw_flag);
#endif


#if (USE_LIST == 0)    
    if(char_dev->char_dev_data_total_used < MAX_DATA_BUF)/*buf 没有满。可以继续写*/
    {
        
    }
    else/*buf 满了，需要等待读取，读取之后在写入*/
    {
        write_sig = 0;
        wait_event_interruptible(cdev_wait,write_sig);
        
        dev_warn(char_dev->char_cdev_device,"write:out of sleep run here\n");
    }

    if(count > MAX_DATA_LEN)
    {
        count = MAX_DATA_LEN;
    }
    write_lock_irqsave(&char_dev->cdev_rw_lock[write_index],rw_flag);
    ret = raw_copy_from_user(char_dev->char_dev_data[write_index].data,buf,count);
    dev_warn(char_dev->char_cdev_device,"write data:%s,len:%ld,used:%d,index:%d!\n",char_dev->char_dev_data[write_index].data,count,char_dev->char_dev_data_total_used,char_dev->char_dev_data_w_index);
    if(ret < 0)
    {
        dev_err(char_dev->char_cdev_device,"kernel write failed!\n");
        return -EFAULT;
    }
    user_read_len = count;
    char_dev->char_dev_data[write_index].data_len = count;
    if(char_dev->char_dev_data_total_used == 0)/*buffer 空，唤醒阻塞的读信号*/
    {
        read_sig = 1;
        wake_up_interruptible(&cdev_wait);
        dev_warn(char_dev->char_cdev_device,"wake up read event\n");
    }

    char_dev->char_dev_data_total_used++;
    if(char_dev->char_dev_data_total_used > MAX_DATA_BUF)
    {
        char_dev->char_dev_data_total_used = MAX_DATA_BUF;
    }
    char_dev->char_dev_data_w_index++;
    if(char_dev->char_dev_data_w_index >= MAX_DATA_BUF)
    char_dev->char_dev_data_w_index = 0;

    //char_dev->list_dev_data.data = vmalloc(count);
    char_dev->list_dev_data.num++;

    write_unlock_irqrestore(&char_dev->cdev_rw_lock[write_index],rw_flag);
#endif
    return ret;
}
static long int char_cdev_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{
    int ret = 0;
    struct C_Dev *char_dev= file->private_data;
    dev_warn(char_dev->char_cdev_device,"ioctl method!\n");
    if (_IOC_TYPE(cmd) != LUAN_TEST_MAGIC) return -ENOTTY;
	if (_IOC_NR(cmd) > LUAN_TEST_CMD_MAX) return -ENOTTY;

    switch(cmd) {
        case READ_LENGTH_CMD:
        ret = raw_copy_to_user((int __user*)arg,&user_read_len,1);
        dev_warn(char_dev->char_cdev_device,"ioctl read length:%d,ret:%d\r\n",user_read_len,ret);
        break;
        case 1:
        break;
        default:
        break;
    }

    return ret;
}
struct file_operations char_cdev_fops = 
{
    .owner = THIS_MODULE,
	.read = char_cdev_read,
    .write = char_cdev_write,
    .open = char_cdev_open,
    .release = char_cdev_release,
    .unlocked_ioctl = char_cdev_ioctl
};
static int __init char_cdev_init(void)
{
    int ret;
    unsigned int i;
    
    if(major >0 )/*静态设备编号*/
    {
        char_device.devno = MKDEV(major,minor);
        ret = register_chrdev_region(char_device.devno,1,DEVICE_NAME);
    }
    else    /*动态设备号*/
    {
        ret = alloc_chrdev_region(&char_device.devno,minor,1,DEVICE_NAME);/*从系统获取主设备号*/
        major = MAJOR(char_device.devno);
    }
    if(ret < 0)
    {
        printk("cannot get major%d\n",major);
        return -1;
    }
    char_device.char_cdev = cdev_alloc();/*分配char_cdev结构*/
    if(char_device.char_cdev != NULL)
    {
        cdev_init(char_device.char_cdev,&char_cdev_fops);/*初始化char_cdev结构*/
        char_device.char_cdev->owner = THIS_MODULE;
        if(cdev_add(char_device.char_cdev,char_device.devno,1)!=0)
        {
            printk("add cdev error!\n");
            goto error;
        }
    }
    else
    {
        printk("add cdev error!\n");
        return -1;
    }
    char_device.char_cdev_class = class_create(THIS_MODULE,"char_cdev_class");
    if(IS_ERR(char_device.char_cdev_class))
    {
        printk("create class error\n");
        return -1;
    }
    char_device.char_cdev_device = device_create(char_device.char_cdev_class,NULL,char_device.devno,NULL,DEVICE_NAME);
    // char_device.cdev_has_data = ATOMIC_INIT(0);/*初始化原子变量并设置值0*/
    for(i=0;i<MAX_DATA_BUF;i++)
    {
        rwlock_init(&char_device.cdev_rw_lock[i]);
    }
    
    init_waitqueue_head(&cdev_wait);/*初始化等待队列*/
    char_dev_data_init();

    return 0;
    
error:
    unregister_chrdev_region(char_device.devno,1);
    return ret;
}
static void __exit char_cdev_exit(void)
{
    cdev_del(char_device.char_cdev);/*移除字符设备*/
    unregister_chrdev_region(char_device.devno,1);/*释放设备号*/
    device_destroy(char_device.char_cdev_class,char_device.devno);
    class_destroy(char_device.char_cdev_class);
}

module_init(char_cdev_init);
module_exit(char_cdev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ASDF");
